#!/usr/bin/python3
from http.server import SimpleHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn
import threading
import re
import os
import time
import hashlib
import io
import sys
class RequestHandler(SimpleHTTPRequestHandler):
	data_num=re.compile("(\\d*)-(\\d*)")
	data_cache_size=1024*10
	def __init__(self, *args, directory=None, **kwargs):
		if directory is None:
			directory = os.getcwd()
		self.directory = os.fspath(directory)
		super().__init__(*args, **kwargs)


	def do_GET(self):
		#主要是想要断点传输文件，目录交给原来的函数处理
		path = self.translate_path(self.path)#模仿父类获取路径
		file_type = os.path.splitext(path)[1]
		file_type = file_type.upper()
		if os.path.isdir(path):
			super().do_GET()
			return
		elif os.path.getsize(path)<100*1024*1024:
			#小于 100MB 的文件文件直接传，不用端点徐传
			super().do_GET()
			return
		#处理文件
		
		if os.path.isfile(path)==False:
			self.send_response(400)
			self.end_headers()
			return
		file_len=os.path.getsize(path)
		if "Range" not in self.headers:
			self.send_response(200)
			self.send_header("Content-Length",str(file_len))
			self.send_header("Content-Type","application/octet-stream")
			file_i=file_len-1
			self.send_header("Content-Range",f"0-{file_i}/{file_len}")
			self.end_headers()
			f=open(path,"rb")
			for i in range(0,file_len,self.data_cache_size):
				bytes1=f.read(self.data_cache_size)
				if self.e_write(bytes1):
					return
			bytes1=f.read(self.data_cache_size)
			if self.e_write(bytes1):
				return
			f.close()
			return

		str_range=self.headers["Range"]
		str_range=str_range.strip()
		if str_range.startswith("bytes=")==False:
			self.send_response(404)
			self.end_headers()
			return
		str_range=str_range[len("bytes="):]
		f=open(path,"rb")
		for i in str_range.split(","):
			data=self.data_num.findall(i)
			data=data[0]
			start=0
			end=0			
			if data[0]!="" and data[1]!="":
				start=int(data[0])
				end=int(data[1])
				len1=end-start+1
			elif data[0]=="" and data[1]!="":
				end=int(data[1])
				f.seek(-end,2)
				start=f.tell()
				end=file_len-1
			elif data[0]!="" and data[1]=="":
				start=int(data[0])
				end=file_len-1
			else:
				#没有有效数据
				self.send_response(404)
				self.end_headers()
				return
			
			print(end-start+1,file_len,path)
			if "Want-Digest" not in self.headers:
				self.send_data(f,start,end,file_len)
				return
			wd=self.headers["Want-Digest"].upper()
			if wd.find("SHA-256")>-1:
				self.send_Digest(f,start,end,file_len)
				return
			self.send_data(f,start,end,file_len)



	def e_write(self,bytes1):
		try:
			self.wfile.write(bytes1)
			return False
		except:
			return True


	def send_Digest(self,f,start,end,file_len,code=200):
		"""start end 都是坐标"""
		assert io.BufferedReader==type(f)
		len1=end-start+1
		if len1>10*1024*1024:
			#拒绝给过大的区块进行校验
			try:
				self.send_response(404)
				self.end_headers()
				return False
			except:
				return True
		f.seek(start,0)
		bytes1=f.read(len1)

		sha256=hashlib.sha256()
		sha256.update(bytes1)
		sha256=sha256.hexdigest()

		try:
			self.send_response(code)
			self.send_header("Content-Length",str(len1))
			self.send_header("Content-Type","application/octet-stream")
			self.send_header("Content-Range",f"{start}-{end}/{file_len}")
			self.send_header("digest",f"SHA-256={sha256}")
			self.end_headers()
			self.wfile.write(bytes1)
			self.wfile.flush()
			return False
		except:
			return True

	def send_data(self,f,start,end,file_len,code=206):
		"""start end 都是坐标"""
		assert io.BufferedReader==type(f)
		len1=end-start+1
		try:
			self.send_response(code)
			self.send_header("Content-Length",str(len1))
			self.send_header("Content-Type","application/octet-stream")
			self.send_header("Content-Range",f"{start}-{end}/{file_len}")
			self.end_headers()
			f.seek(start,0)
			if len1<self.data_cache_size:
				bytes1=f.read(len1)
				self.wfile.write(bytes1)
				return False
			
			for i in range(0,file_len,self.data_cache_size):
				bytes1=f.read(self.data_cache_size)
				if self.e_write(bytes1):
					return True
			bytes1=f.read(len1%self.data_cache_size)
			if self.e_write(bytes1):
				return True
		except:
			return True


class ThreadingHTTPServer(ThreadingMixIn,HTTPServer):
	pass




if __name__ == "__main__":
	print("启动")
	prot = 8080
	if len(sys.argv)>1:
		try:
			prot = int(sys.argv[1])
		except ValueError:
			print("端口错误，使用8080启动")
			prot = 8080
	httpd = ThreadingHTTPServer(("",prot),RequestHandler)
	try:
		httpd.serve_forever()
	except KeyboardInterrupt:
		httpd.server_close()

